package com.example.wacoffeegateway.Filter;

import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.jwt.Claims;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import com.example.wacoffeegateway.utils.CurrentHoler;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;



/**
 * 全局认证过滤器
 * 处理请求的认证和授权逻辑，验证JWT令牌并设置当前用户上下文
 *
 * @author czwa
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class AuthGlobalFilter implements Ordered, GlobalFilter {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    // 无需认证的白名单路径
    private static final List<String> EXCLUDE_PATHS = Arrays.asList(
            "/cart/condition",
            "/me/login",
            "/register",
            "/",
            "/cart",
            "/getCode"
    );

    /**
     * 核心过滤逻辑
     * 1. 检查路径是否在白名单
     * 2. 从请求头获取JWT令牌
     * 3. 验证令牌有效性和时效性
     * 4. 校验Redis中的令牌状态
     * 5. 设置当前用户上下文并传递给后续处理
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        // 检查路径是否在白名单，直接放行
        if (isExcludePath(request.getURI().getPath())) {
            return chain.filter(exchange);
        }

        String token = null;
        // 从请求头获取Authorization字段
        if (request.getHeaders().containsKey("Authorization")) {
            List<String> headers = request.getHeaders().get("Authorization");
            if (!CollectionUtils.isEmpty(headers)) {
                token = headers.get(0);
            }
        }

        // 令牌为空则返回未授权
        if (token == null || token.equals("")) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        ServerHttpResponse response = exchange.getResponse();
        // 移除Bearer前缀
        token = token.replace("Bearer ", "");

        try {
            System.out.println("token:" + token);
            // 解析并验证JWT令牌
            JWT jwt = JWTUtil.parseToken(token);
            if (!jwt.setKey("czwa".getBytes()).verify()) {
                log.info("token解析失败，请重新登录");
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
            // 验证令牌有效期
            JWTValidator.of(jwt).validateDate();
        } catch (Exception e) {
            e.printStackTrace();
            log.info("登陆过期啦，请重新登录");
            CurrentHoler.remove();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 从令牌载荷中获取用户ID
        Claims claims = JWTUtil.parseToken(token).getPayload();
        Object id = claims.getClaim("id");
        String userId = id.toString();

        // 检查Redis中令牌状态
        if (CurrentHoler.getCurrentId() == null) {
            // 首次登录，设置令牌到Redis（15分钟过期）
            stringRedisTemplate.opsForValue().setIfAbsent("user:" + userId, token, Duration.of(15, ChronoUnit.MINUTES));
        } else if (!stringRedisTemplate.hasKey("user:" + userId)) {
            // Redis中无令牌，说明已过期
            CurrentHoler.remove();
            log.info("当前用户" + CurrentHoler.getCurrentId() + "登陆过期啦，请重新登录");
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        } else {
            // 刷新令牌过期时间
            stringRedisTemplate.expire("user:" + userId, Duration.of(15, ChronoUnit.MINUTES));
        }

        log.info("用户ID: {}", id);
        // 设置当前用户ID到线程本地存储
        CurrentHoler.set(Integer.valueOf(id.toString()));
        // 在请求头中添加user-id字段传递给下游服务
        ServerWebExchange ex = exchange.mutate()
                .request(b -> b.header("user-id", userId))
                .build();
        return chain.filter(ex);
    }

    /**
     * 检查路径是否在白名单
     * 使用AntPathMatcher进行路径匹配
     */
    private boolean isExcludePath(String path) {
        return EXCLUDE_PATHS.stream()
                .anyMatch(pattern -> antPathMatcher.match(pattern, path));
    }

    /**
     * 设置过滤器执行顺序（数值越小优先级越高）
     */
    @Override
    public int getOrder() {
        return 0;
    }
}